<template>
    <div class="person">
        <h1>case1: 监视[ref]定义的[基本类型]数据</h1>
        <h2>求和sum: {{ sum }}</h2>
        <button @click="changeSum">点我+1</button>
        <hr>
        <h1>case2: 监视[ref]定义的[对象类型]数据</h1>
        <h2>姓名: {{ person.name }}</h2>
        <h2>年龄: {{ person.age }}</h2>
        <button @click="changeName">修改名字</button>
        <button @click="changeAge">修改年龄</button>
        <button @click="changePerson">修改人</button>
        <hr>
        <h1>case3: 监视[reactive]定义的[对象类型]数据</h1>
        <h2>姓名: {{ person2.name }}</h2>
        <h2>年龄: {{ person2.age }}</h2>
        <button @click="changeName2">修改名字</button>
        <button @click="changeAge2">修改年龄</button>
        <button @click="changePerson2">修改人</button>
        <hr>
        <h1>case4: 监视[ref]或[reactive]定义的[对象类型]数据中的某个属性</h1>
        <h2>注意:1,若该属性不是[对象类型],需要写成函数形式</h2>
        <h2>2,若该属性是[对象类型],则可直接监视,也可写成函数,建议写成函数</h2>
        <h2>姓名: {{ person3.name }}</h2>
        <h2>年龄: {{ person3.age }}</h2>
        <h2>车1: {{ person3.car.c1 }}</h2>
        <h2>车2: {{ person3.car.c2 }}</h2>
        <button @click="changeName3">修改名字</button>
        <button @click="changeAge3">修改年龄</button>
        <button @click="changePerson3Car1">修改车1</button>
        <button @click="changePerson3Car2">修改车2</button>
        <button @click="changePerson3Car">修改整个车</button>
        <hr>
        <h1>case5: 上述多个数据组成的数组</h1>
    </div>
</template>

<script lang="ts">
export default {
    name: 'Person',
}
</script>


<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
let sum = ref(0)
const changeSum = () => {
    sum.value++
}
// 可以监视4种数据:
// 1. ref定义的数据,包括基本类型和对象类型的数据
// 2. reactive定义的数据,只有对象类型的数据
// 3, 函数返回一个值(getter函数)
// 4, 一个包含上述内容的数组
const stopWatch = watch(sum, (newValue, oldValue) => {
    console.log(newValue, oldValue)
    if (sum.value > 10) {
        // 解除监视
        stopWatch()
    }
})

let person = ref({
    name: '张三',
    age: 18,
})
const changeName = () => {
    person.value.name += "~"
}
const changeAge = () => {
    person.value.age++
}
const changePerson = () => {
    person.value = {
        name: '李四',
        age: 20,
    }
}
// 监视person的地址值,若想监视对象内部属性的变化,需要手动开启深度监视
watch(person, (newValue, oldValue) => {
    console.log(person, newValue, oldValue)
}, {
    // 注意, 监视的始终是地址值,因此当对象内部属性变化时,地址不变,新旧值都是同一个地址,且回调函数中的旧值与新值一致
    // 但如果是changePerson引起的回调,则整个对象都变化了,新旧值就不同.实际开发中通常只处理第一个参数,即新值,因此不必关心旧值是否真正的旧值
    deep: true, // deep:true 表示监视对象内部属性的变化
    immediate: true  // immediate:true 表示初始化时执行一次回调
})

let person2 = reactive({
    name: '张三',
    age: 18,
})
const changeName2 = () => {
    person2.name += "~"
}
const changeAge2 = () => {
    person2.age++
}
const changePerson2 = () => {
    Object.assign(person2, {
        name: '李四',
        age: 20,
    })
}
// 当监视reactive对象时,默认开启深度监视,且无法关闭(隐式创建深层监听)
watch(person2, (newValue, oldValue) => {
    console.log('person2变化了', newValue, oldValue)
}, {
    deep: false // 此处deep设置为false,无效
})

let person3 = reactive({
    name: '张三',
    age: 18,
    car: {
        c1: "奇瑞",
        c2: "宝骏"
    }
})
const changeName3 = () => {
    person3.name += "~"
}
const changeAge3 = () => {
    person3.age++
}
const changePerson3Car1 = () => {
    person3.car.c1 += "$"
}
const changePerson3Car2 = () => {
    person3.car.c2 += "&"
}
const changePerson3Car = () => {
    person3.car = { c1: "五菱", c2: "马自达" }
}
// 监视对象中的基本属性, 此处监视的是一个getter函数,所谓getter函数,就是一个有返回值的函数
// watch(person3.name, (newValue, oldValue) => {
watch(() => {
    console.log("person3.name被监视", person3.name)
    person3.name // 隐含了return的getter函数
}, (newValue, oldValue) => {
    console.log("person3.name", newValue, oldValue)
})
// 监视对象中的对象的基本属性
watch(() => person3.car.c1, (newValue, oldValue) => {
    console.log("person3.car.c1", newValue, oldValue)
})
// 监视对象中的对象,可以直接监视对象,也可以写函数来监视,建议用函数(why)
// 因为,如果是直接监视对象,则修改了person3.car整体后,地址值变化,不会监听变化后的地址,即后续属性的变化不会再回调此函数
watch(person3.car, (newValue, oldValue) => {
    console.log("person3.car 变化", newValue, oldValue)
})
// 如果是通过函数返回值监视,则当person3.car变化时,会回调此函数,但内部属性的变化依然不会回调此函数
// 如果想要监视内部属性,则需要设置deep为true
watch(() => person3.car, (newValue, oldValue) => {
    console.log("=> person3.car 变化", newValue, oldValue)
}, { deep: true })

watch([() => person3.car, () => person3.car.c1], (newValue, oldValue) => {
    console.log("=> 同时监听多个数据 有变化", newValue, oldValue)
})
</script>

<style scoped>
.person {
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}

button {
    margin: 0 2px;
}

li {
    font-size: 15px;
}
</style>